Day 12 已經可以把新增任務真的存進 MySQL。
但首頁還有一個問題:
index.html
裡面的任務卡片仍然是以前手動寫死的假資料。
所以 Day 13 的目標是:
把首頁改成直接讀取 MySQL 裡真正的任務。
今天先只做「顯示資料」,不碰:
編輯
刪除
狀態修改
篩選
分類 CRUD
Claude API
我先告訴 Claude Code 目前的狀態:
目前狀態:
- Flask 已經成功連上 MySQL
- 已有 Category、Task Model
- /tasks/new 已經可以新增任務到 MySQL
- index.html 目前還是三筆寫死的假資料
今天只做:
1. 首頁從 MySQL 查詢所有 Task
2. 把 tasks 傳給 index.html
3. 使用 Jinja2 迴圈顯示任務
4. 顯示:
- 任務名稱
- 狀態
- 分類
- 截止日期
5. 移除原本三筆寫死的假資料
6. 沒有任務時顯示簡單提示
今天不要:
- 編輯
- 刪除
- 狀態修改
- 篩選
- 分類 CRUD
- services/
- routes/
- Claude API
請先規劃會修改哪些檔案,
不要直接修改程式。
最後確認只會修改:
app.py
models/task.py
templates/index.html
原本首頁只是:
@app.route("/")
def index():
return render_template("index.html")
Day 13 改成:
@app.route("/")
def index():
tasks = Task.query.order_by(
Task.created_at.desc(),
Task.id.desc(),
).all()
return render_template("index.html", tasks=tasks)
這裡最重要的是:
Task.query
代表透過 Task Model 查詢 tasks 資料表。
而:
.all()
代表把所有任務查出來。
這次使用:
Task.created_at.desc(),
Task.id.desc(),
代表:
建立時間新的先顯示
↓
如果建立時間相同
↓
id 比較大的先顯示
這樣剛新增的任務會比較穩定地出現在首頁最上面。
tasks 裡其實只存:
category_id
例如:
category_id = 3
但首頁想看到的是:
生活
所以在 models/task.py 加入:
category = db.relationship("Category")
這樣之後就可以直接:
task.category.name
task.category.color
不需要自己拿 category_id 再查一次。
MySQL 裡的狀態存的是:
todo
in_progress
done
但首頁要顯示:
待處理
進行中
已完成
所以 Task Model 加入:
STATUS_LABELS = {
"todo": "待處理",
"in_progress": "進行中",
"done": "已完成",
}
以及:
@property
def status_label(self):
return self.STATUS_LABELS.get(self.status, self.status)
這樣首頁就可以直接:
{{ task.status_label }}
Day 8 已經有:
status-todo
status-progress
status-done
其中資料庫的 in_progress 對應到既有 CSS 的 status-progress,
兩邊名稱不完全相同,所以透過 STATUS_CSS_CLASSES 做轉換。
所以這次也加:
STATUS_CSS_CLASSES = {
"todo": "status-todo",
"in_progress": "status-progress",
"done": "status-done",
}
以及:
@property
def status_css_class(self):
return self.STATUS_CSS_CLASSES.get(self.status, "")
首頁就可以寫:
<span class="status-badge {{ task.status_css_class }}">
{{ task.status_label }}
</span>
資料庫仍然存英文值,畫面才負責顯示中文和樣式。
Day 8 的首頁是三張手動寫死的:
<article class="task-card">
...
</article>
Day 13 改成:
{% for task in tasks %}
所以現在不是固定三張卡片,而是:
MySQL 有幾筆 Task
↓
首頁就顯示幾張卡片
任務名稱:
<h2>{{ task.title }}</h2>
狀態:
<span class="status-badge {{ task.status_css_class }}">
{{ task.status_label }}
</span>
分類部分:
{% if task.category %}
<span
class="category-dot"
style="background-color: {{ task.category.color }}">
</span>
{{ task.category.name }}
{% else %}
未分類
{% endif %}
如果任務有分類,就顯示:
● 專案
如果 category_id 是 NULL,則顯示:
未分類
截止日期:
{% if task.due_date %}
<time datetime="{{ task.due_date }}">
{{ task.due_date.strftime('%Y/%m/%d') }}
</time>
{% else %}
未設定
{% endif %}
例如資料庫裡:
2026-10-01
首頁會顯示:
2026/10/01
如果沒有截止日期,就顯示:
未設定
首頁原本就有:
task-completed
用來顯示已完成任務。
現在改成:
<article class="task-card{% if task.status == 'done' %} task-completed{% endif %}">
所以只有:
status = done
的任務才會套用完成樣式。
Jinja2 的 for 可以搭配 else:
{% for task in tasks %}
...
{% else %}
<p class="empty-state">
目前沒有任務,點右上角「新增任務」開始新增。
</p>
{% endfor %}
如果 tasks 是空的,首頁不會整片空白,而是顯示提示。
目前 MySQL 裡有兩筆資料。
首頁現在會直接顯示:
測試1
進行中
生活
2026/10/01
測試
待處理
專案
2026/09/26

可以看到原本寫死的:
整理期末專題需求
完成首頁介面設計
建立 Flask 專案骨架
已經全部消失。
再回到 MySQL Workbench:
SELECT * FROM tasks;
可以看到首頁顯示的兩筆資料確實存在 MySQL。
兩張圖對照後,可以確認:
MySQL
↓
Task Model
↓
Flask
↓
Jinja2
↓
首頁任務卡片
已經真的接起來。
Day 12 已經可以新增任務。
所以現在再從:
/tasks/new
新增一筆資料後,回到首頁,就會直接看到新任務。
而且因為首頁有排序:
Task.created_at.desc(),
Task.id.desc(),
最新任務會顯示在前面。
Day 13 完成後,首頁終於不再依賴寫死的假資料。
目前已經可以做到:
新增任務
↓
存進 MySQL
↓
重新讀取
↓
首頁顯示
而且狀態、分類、截止日期也都能正常顯示。
目前還不能修改或刪除既有任務。
所以下一步就是開始補 CRUD 的 Update。